/**
 * @file linked_list.h
 * @author 樊少冰
 * @date 2019 年 3 月 21 日
 * @desc 链表 数据结构 头文件
 * From CLC project
 */

#ifndef LIBCX_LINKED_LIST_H
#define LIBCX_LINKED_LIST_H

#include <stdint.h>
#include <string.h>


/**
 * 链表结点结构体
 */
struct link {
    struct link *prev;
    struct link *next;
    uint8_t data[0];
};


/**
 * 链表节点类型定义
 */
typedef struct link link_t;


/**
 * 链表结构体
 */
struct linked_list {
    link_t *first;        // First element pointer
    link_t *last;         // Last element pointer
    size_t  length;       // Amount of elements
    size_t  elem_size;    // Each element's size
};


/**
 * 链表数据类型
 */
typedef struct linked_list linked_list_t;


/**
 * @param T type
 * @desc
 * 创建一个数据类型是 T 的链表
 * 例如:
 * `NEW_LINKED_LIST(int)`
 */
#define NEW_LINKED_LIST(T) (new_linked_list(sizeof(T)))

linked_list_t *
new_linked_list (size_t elem_size);


/**
 * @param OBJ linked_list_t *
 * @desc
 * 从内存中删除一个链表（包括里面的数据）
 * 例如:
 * `FREE_LINKED_LIST(linked_list_object)`
 */
#define FREE_LINKED_LIST(OBJ) (free_linked_list(OBJ))

void
free_linked_list (linked_list_t *obj);


/**
 * @param OBJ linked_list_t *
 * @param ELEMENT [一个内存中的对象]
 * @returns int
 * @desc
 * 在一个链表的末端追加一个元素（该元素必须是内存中的对象）
 * 例如:
 * ```
 * int a = 123;
 * LINKED_LIST_APPEND(list, a);
 * ```
 */
#define LINKED_LIST_APPEND(OBJ, ELEMENT) (linked_list_append(OBJ, &(ELEMENT)))

/**
 * @param OBJ linked_list_t *
 * @param TYPE [立即数的类型]
 * @param IMM [立即数]
 * @desc
 * 在一个链表的末端追加一个立即数元素
 * 例如:
 * `LINKED_LIST_APPEND_IMM(list, int, 123)`
 */
#define LINKED_LIST_APPEND_IMM(OBJ, TYPE, IMM) ({ \
    TYPE __buffer_ = IMM; \
    linked_list_append(OBJ, &__buffer_); \
})

int
linked_list_append (linked_list_t *obj, void *ptr_elem);


/**
 * @param OBJ linked_list_t *
 * @param OFFSET [整数型]
 * @param TYPE [类型]
 * @returns TYPE *
 * @desc
 * 获取从 0 开始的第 OFFSET 个元素的 TYPE 类型的指针
 * 例如:
 * `LINKED_LIST_GET(list, 0, int)`
 * 会获取第 0 个元素的 int* 类型的指针
 */
#define LINKED_LIST_GET(OBJ, OFFSET, TYPE) ((TYPE *)linked_list_get(OBJ, OFFSET))

void *
linked_list_get (linked_list_t *obj, size_t offset);


/**
 * @param OBJ linked_list_t *
 * @param ELEMENT [循环中元素指针的名称]
 * @param TYPE [元素数据类型]
 * @param ACTION [循环体]
 * @desc 链表的 foreach 循环宏
 * 例如：
 * LINKED_LIST_FOREACH(list, e, int, {
 *     printf("foreach: %d", *e);
 * });
 */
#define LINKED_LIST_FOREACH(OBJ, ELEMENT, TYPE, ACTION) ({\
    link_t *__ptr_; \
    TYPE *ELEMENT; \
    for (__ptr_ = (OBJ)->first; __ptr_ != NULL; __ptr_ = __ptr_->next) { \
        ELEMENT = (TYPE *)(__ptr_->data);\
        {ACTION;}\
	}\
})


/**
 * @param OBJ linked_list_t *
 * @param ELEMENT [循环中元素指针的名称]
 * @param TYPE [元素数据类型]
 * @param ACTION [循环体]
 * @desc 链表的 foreach 循环宏（倒序）
 * 例如：
 * LINKED_LIST_FOREACH_BACKWARD(list, e, int, {
 *     printf("foreach: %d", *e);
 * });
 */
#define LINKED_LIST_FOREACH_BACKWARD(OBJ, ELEMENT, TYPE, ACTION) ({\
    link_t *__ptr_; \
    TYPE *ELEMENT; \
    for (__ptr_ = (OBJ)->last; __ptr_ != NULL; __ptr_ = __ptr_->prev) { \
        ELEMENT = (TYPE *)(__ptr_->data);\
        {ACTION;}\
	}\
})


/**
 * @param OBJ linked_list_t *
 * @param OFFSET [插入位置]
 * @param ELEMENT [要插入的元素（必须在内存中）]
 * @returns int
 * @desc
 * 将链表的 OFFSET 位置上的元素及其之后的全部元素后移并将新元素插入链表的 OFFSET 位置，
 * 如果出错会返回 -1
 * 例如：
 * `LINKED_LIST_INSERT(list, 2, a)`
 */
#define LINKED_LIST_INSERT(OBJ, OFFSET, ELEMENT) (linked_list_insert((OBJ), OFFSET, &(ELEMENT)))

/**
 * @param OBJ linked_list_t *
 * @param OFFSET [插入位置]
 * @param TYPE [要插入的元素的类型]
 * @param IMM [要插入的元素（立即数）]
 * @returns int
 * @desc
 * 将链表的 OFFSET 位置上的元素及其之后的全部元素后移并将新元素插入链表的 OFFSET 位置，
 * 如果出错会返回 -1
 * 例如：
 * `LINKED_LIST_INSERT_IMM(list, 0, 123)`
 */
#define LINKED_LIST_INSERT_IMM(OBJ, OFFSET, TYPE, IMM) ({\
    TYPE __buffer_ = IMM; \
    linked_list_insert((OBJ), OFFSET, &__buffer_); \
})

int
linked_list_insert (linked_list_t *obj, size_t offset, void *ptr_data);


/**
 * @param OBJ linked_list_t *
 * @param OFFSET int
 * @returns int
 * @desc
 * 将链表的 OFFSET 位置上的元素删除，
 * 如果出错会返回 -1
 * 例如：
 * `LINKED_LIST_DELETE(list, 0)`
 */
#define LINKED_LIST_DELETE(OBJ, OFFSET) (linked_list_delete(OBJ, OFFSET))

int
linked_list_delete (linked_list_t *obj, size_t offset);


/**
 * @param OBJ linked_list_t *
 * @param OFFSET int
 * @returns int
 * @desc
 * 将链表中的所有元素删除，
 * 如果出错会返回 -1
 * 例如：
 * `LINKED_LIST_DELETE_ALL(list)`
 */
#define LINKED_LIST_DELETE_ALL(OBJ) (linked_list_delete_all(OBJ))

int
linked_list_delete_all (linked_list_t *obj);


/**
 * @param OBJ linked_list_t *
 * @param OFFSET int
 * @returns int
 * @desc
 * 将两个链表对接成一个链表（第二个链表会失效）
 * 例如：
 * `LINKED_LIST_DELETE_ALL(list)`
 */
#define LINKED_LIST_CONCAT(OBJ, ANOTHER) (linked_list_concat(OBJ, ANOTHER))

int
linked_list_concat (linked_list_t *obj, linked_list_t *another);


#endif // LIBCX_LINKED_LIST_H
